package com.netease.framework.skin;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;


public class SkinManager {
	private static SkinManager mSkinManager = null;

	private static int[] resArrayBackground;
	private static int[] resArrayTextColor;
	private static int[] resArrayDivider;
	private static int[] resArraySrc;
	private static int[] resArrayDrawableLeft;
	private static int[] resArrayCBbg;
	static {
		resArrayBackground = new int[] { android.R.attr.background, };
		resArrayTextColor = new int[] { android.R.attr.textColor, };
		resArrayDivider = new int[] { android.R.attr.divider };
		resArraySrc = new int[] { android.R.attr.src };
		resArrayDrawableLeft = new int[] { android.R.attr.drawableLeft };
		resArrayCBbg = new int[] { android.R.attr.button };
	}

	public final static String SKINPACKAGE = "pris\\.skin\\..*";
	public final static String SKIN_INTERNAL = "internal\\.skin\\..*";
	public static final String SKIN_INTERNAL_BLACK = "internal.skin.black";

	public static SkinManager getInstance(Context context) {
		if (null != mSkinManager) {
			return mSkinManager;
		}
		initialize(context);
		return mSkinManager;
	}

	private static void initialize(Context context) {
		mSkinManager = null;
		if (null != context) {
			mSkinManager = new SkinManager(context.getApplicationContext());
		}
	}

	private Context mContext = null;
	private IResources mRes;
	private Resources mDefaultRes;
	private Skin mUsingSkin;
	private WeakHashMap<View, ViewSkinResource> mViewResMap = new WeakHashMap<View, ViewSkinResource>();
	private String mPkgName;
	private PackageManager mPkgMgr;

	private SkinManager(Context context) {
		mContext = context;
		mDefaultRes = mContext.getResources();
		mPkgName = mContext.getPackageName();
		mPkgMgr = mContext.getPackageManager();
		initUsingSkin();
	}

	public void initUsingSkin() {
		String pkgName = null;
		if (TextUtils.isEmpty(pkgName) || mPkgName.equals(pkgName)) {
			mUsingSkin = getDefaultSkin();
			return;
		}

		if (pkgName.equals(SKIN_INTERNAL_BLACK)) {
			mUsingSkin = getInternalBlackSkin();
			return;
		}

		Skin skin = getInstalledSkinForName(pkgName);
		if (null == skin) {
			skin = getDefaultSkin();
		}

		mUsingSkin = skin;
	}
	
	private Skin getInternalBlackSkin() {
	    Skin sk = new Skin();
	    sk.setPackageName(SkinManager.SKIN_INTERNAL_BLACK);
	    sk.setInstalled(true);
	    sk.setUsing(true);
	    sk.setPreviewPic(null);
		
	    return sk;
	}

	public void setNewSkin(Skin skin) {
		mUsingSkin = (null == skin) ? getDefaultSkin() : skin;
	}

	public Skin getUsingSkin() {
		if (null == mUsingSkin) {
			mUsingSkin = getDefaultSkin();
		}
		return mUsingSkin;
	}

	public boolean isUsingDefaultSkin() {
		if (null == mUsingSkin) {
			mUsingSkin = getDefaultSkin();
			return true;
		}
		boolean res = mPkgName.equals(mUsingSkin.getPackageName());

		return res;
	}

	public void setResourceFactory(IResources inRes) {
		mRes = inRes;
		if (null == mRes) {
			mUsingSkin = getDefaultSkin();
		}
	}

	public IResources getResourceFactory() {
		return mRes;
	}

	public void addView(View view, AttributeSet attrs) {
		if (null == view || null == attrs) {
			return;
		}
		ViewSkinResource resMap = new ViewSkinResource();
		int resId = -1;

		resId = getResourceId(attrs, resArrayBackground);
		if (resId > 0) {
			resMap.setBackgroundResId(resId);
		}

		resId = getResourceId(attrs, resArrayTextColor);
		if (resId > 0) {
			resMap.setTextColorResId(resId);
		}

		resId = getResourceId(attrs, resArrayDivider);
		if (resId > 0) {
			resMap.setDividerResId(resId);
		}

		resId = getResourceId(attrs, resArraySrc);
		if (resId > 0) {
			resMap.setSrcResId(resId);
		}

		resId = getResourceId(attrs, resArrayDrawableLeft);
		if (resId > 0) {
			resMap.setDrawableLeftResId(resId);
		}

		resId = getResourceId(attrs, resArrayCBbg);
		if (resId > 0) {
			resMap.setCheckBoxBtnResId(resId);
		}
		synchronized (mViewResMap) {
			mViewResMap.put(view, resMap);
		}

		if (!isUsingDefaultSkin()) {
			setViewSkin(view, resMap);
		}
	}

	public int getViewResMapSize() {
		return mViewResMap.size();
	}

	private int getResourceId(AttributeSet attrs, int[] checkAttrs) {
		if (null == attrs || null == checkAttrs || checkAttrs.length == 0) {
			return -1;
		}

		TypedArray a = mContext.obtainStyledAttributes(attrs, checkAttrs);
		TypedValue value = a.peekValue(0);

		int resId = -1;
		if (value != null) {
			resId = value.resourceId;
		}
		a.recycle();

		return resId;
	}

	public void onSkinChange() {
		synchronized (mViewResMap) {
			Set<Entry<View, ViewSkinResource>> keys = mViewResMap.entrySet();
			Iterator<Entry<View, ViewSkinResource>> iter = keys.iterator();
			Map.Entry<View, ViewSkinResource> en = null;
			View key = null;
			ViewSkinResource value = null;

			while (iter.hasNext()) {
				en = iter.next();
				key = (View) en.getKey();
				value = (ViewSkinResource) en.getValue();

				if (null == value) {
					continue;
				}

				setViewSkin(key, value);
			}
		}
	}

	private void setViewSkin(View v, ViewSkinResource resMap) {
		if (null == v || null == resMap) {
			return;
		}

		int id = -1;
		id = resMap.getBackgroundResId();
		if (id > 0) {
			Drawable d = getDrawable(id);
			setBackgroundDrawable(v, d);
		}

		id = resMap.getTextColorResId();
		if (id > 0 && (v instanceof TextView)) {
			((TextView) v).setTextColor(getColor(id));
		}

		id = resMap.getDrawableLeftResId();
		if (id > 0 && (v instanceof TextView)) {
			((TextView) v).setCompoundDrawablesWithIntrinsicBounds(
					getDrawable(id), null, null, null);
		}

		id = resMap.getDividerResId();
		if (id > 0 && (v instanceof ListView)) {
			((ListView) v).setDivider(getDrawable(id));
		}

		id = resMap.getSrcResId();
		if (id > 0 && (v instanceof ImageView)) {
			((ImageView) v).setImageDrawable(getDrawable(id));
		}

		id = resMap.getCheckBoxBtnResId();
		if (id > 0 && (v instanceof CheckBox)) {
			((CheckBox) v).setButtonDrawable(getDrawable(id));
		}
	}

	public static void setBackgroundDrawable(View v, Drawable d) {
		if (null == v || null == d) {
			return;
		}

		int pl = v.getPaddingLeft();
		int pt = v.getPaddingTop();
		int pr = v.getPaddingRight();
		int pb = v.getPaddingBottom();
		v.setBackgroundDrawable(d);
		v.setPadding(pl, pt, pr, pb);
	}

	public int getIdentifier(int id) {
		if (null == mRes) {
			return id;
		}

		int newId = mRes.getIdentifier(id);
		if (newId <= 0) {
			return id;
		}

		return newId;
	}

	public Drawable getDrawable(int id) throws Resources.NotFoundException {
		if (null == mRes) {
			return mDefaultRes.getDrawable(id);
		}

		Drawable d = null;
		try {
			d = mRes.getDrawable(id);
		} catch (Resources.NotFoundException e) {
			return mDefaultRes.getDrawable(id);
		}

		return null == d ? mDefaultRes.getDrawable(id) : d;
	}

	public int getColor(int id) throws Resources.NotFoundException {
		if (null == mRes) {
			return mDefaultRes.getColor(id);
		}

		int color = -1;
		try {
			color = mRes.getColor(id);
		} catch (Resources.NotFoundException e) {
			return mDefaultRes.getColor(id);
		}

		return color;
	}

	public ColorStateList getColorStateList(int id) {
		ColorStateList list = null;
		if (null == mRes) {
			return mDefaultRes.getColorStateList(id);
		}

		try {
			list = mRes.getColorStateList(id);
		} catch (Resources.NotFoundException e) {
			return mDefaultRes.getColorStateList(id);
		}

		return list;
	}

	public Skin getSkinInfo(String filePath, PackageManager pm,
			PackageInfo pkgInfo, boolean isInstalled) {
		if (null == pm || null == pkgInfo) {
			return null;
		}
		Skin skin = new Skin();
		skin.setFilePath(filePath);
		ApplicationInfo appInfo = pkgInfo.applicationInfo;

		String pkgName = appInfo.packageName;
		skin.setPackageName(pkgName);
		if (mPkgName.equals(pkgName)) {
			skin.setDisplayName(null);
		} else {
			skin.setDisplayName(pm.getApplicationLabel(appInfo).toString());
			skin.setPreviewPic(pm.getApplicationIcon(appInfo));
		}

		skin.setVersion(pkgInfo.versionName);
		skin.setInstalled(isInstalled);

		skin.setUsing(true);

		return skin;
	}

	private class ViewSkinResource {
		private int _backgroundResId = -1;
		private int _textColorResId = -1;
		private int _dividerResId = -1;
		private int _srcResId = -1;
		private int _drawableLeftResId = -1;
		private int _Cb_button_bg = -1;

		public int getBackgroundResId() {
			return _backgroundResId;
		}

		public int getTextColorResId() {
			return _textColorResId;
		}

		public int getDividerResId() {
			return _dividerResId;
		}

		public int getSrcResId() {
			return _srcResId;
		}

		public int getDrawableLeftResId() {
			return _drawableLeftResId;
		}

		public int getCheckBoxBtnResId() {
			return _Cb_button_bg;
		}

		public void setBackgroundResId(int id) {
			_backgroundResId = id;
		}

		public void setTextColorResId(int id) {
			_textColorResId = id;
		}

		public void setDividerResId(int id) {
			_dividerResId = id;
		}

		public void setSrcResId(int id) {
			_srcResId = id;
		}

		public void setDrawableLeftResId(int id) {
			_drawableLeftResId = id;
		}

		public void setCheckBoxBtnResId(int id) {
			_Cb_button_bg = id;
		}
	}

	public Skin getDefaultSkin() {
		PackageInfo pkgInfo = null;
		try {
			pkgInfo = mPkgMgr.getPackageInfo(mContext.getPackageName(), 0);
		} catch (NameNotFoundException e1) {
			e1.printStackTrace();
		}
		return getSkinInfo(null, mPkgMgr, pkgInfo, true);
	}

	public Skin getInstalledSkinForName(String name) {
		if (TextUtils.isEmpty(name)) {
			return null;
		}

		PackageInfo pkgInfo = null;
		try {
			pkgInfo = mPkgMgr.getPackageInfo(name, PackageManager.GET_ACTIVITIES);
		} catch (PackageManager.NameNotFoundException e) {
			e.printStackTrace();
		}
		return getSkinInfo(null, mPkgMgr, pkgInfo, true);
	}
}
